package com.gxa.clientadmin.utils;

/*
 *
 *@author leijun
 *
 *@creating 2020/11/17 9:06
 *
 */

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.SneakyThrows;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.Map;

/**
 * @ClassName JWTUtils
 * @Description TODO
 * @Author 俊
 * @Date 2020/11/17 9:06
 * @Version 1.0
 */
public class JWTUtils {
    /**
     * 创建JWT的方法
     * @param id 一般提供一个唯一的用于区分jwt的标识
     * @param subject json字符串,
     * @param ttlMillis 时效,单位毫秒
     * @param claims 存放需要还原的数据,是一个Map
     * @return 返回一个jwt的字符串
     * @throws Exception
     */
    @SneakyThrows
    public String createJWT(String id, String subject, long ttlMillis)  {
        // 指定签名的时候使用jjwt提供的签名算法，也就是header那部分，jjwt已经将这部分内容封装好了。
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;

        // 生成JWT的生存时间
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        //调用生成加密key的方法
        SecretKey key = generalKey();

        //为payload添加标准声明和私有声明
        // 开始创建一个JwtBuilder，设置jwt的body
        JwtBuilder builder = Jwts.builder()
//                .setClaims(claims) // 如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
                .setId(id) // 设置jti(JWT
                // ID)：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token
                .setIssuedAt(now) // iat: jwt的签发时间
                .setSubject(subject) //表示JWT的主体，即JWT的所有人，是一个json格式的字符串，作为用户的唯一标志。
                .signWith(signatureAlgorithm, key);// 设置签名使用的签名算法和签名使用的秘钥

        // 设置过期时间:当用户指定jwt生存时间ttlMillis合法,则在jwt生成时间基础上叠加
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);
            builder.setExpiration(exp);
        }
        return builder.compact(); // 就开始压缩为xxxxxxxxxxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxx格式的jwt
    }

    /**
     * 解密jwt
     * @param jwt  要被验证的jwt字符串
     * @return 返回Claims对象  带有所有添加在jwt上的字段特征
     * @throws Exception
     */
    public Claims parseJWT(String jwt) throws Exception {
        SecretKey key = generalKey(); // 签名秘钥，和生成的签名的秘钥一模一样
        Claims claims = Jwts.parser() // 得到DefaultJwtParser
                .setSigningKey(key)   // 设置签名的秘钥
                .parseClaimsJws(jwt).getBody();// 设置需要解析的jwt
        return claims;
    }

    /**
     * 由字符串生成加密key,此处使用ehome通过Base64生成
     * @return
     */
    public SecretKey generalKey() {
        //Java 8的java.util套件中，新增了Base64的类别，可以用来处理Base64的编码与解码
        // 此处编码内容是通过ehome字符串生成
        byte[] encodedKey = Base64.getDecoder().decode("ZWhvbWU=");// 本地的密码解码(是"ehome" 经过base64 编码之后的结果)
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");// 根据给定的字节数组使用AES加密算法构造一个密钥，使用
        return key;
    }
}
